/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.workflow.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import me.zhengjie.modules.workflow.domain.ActReModel;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.workflow.repository.ProcessCategoryRepository;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.workflow.repository.ActReModelRepository;
import me.zhengjie.modules.workflow.service.ActReModelService;
import me.zhengjie.modules.workflow.service.dto.ActReModelDto;
import me.zhengjie.modules.workflow.service.dto.ActReModelQueryCriteria;
import me.zhengjie.modules.workflow.service.mapstruct.ActReModelMapper;
import me.zhengjie.modules.workflow.vo.ModelVo;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.util.MultiValueMap;

import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
 * @author wzp
 * @website https://el-admin.vip
 * @description 服务实现
 * @date 2020-10-28
 **/
@Service
@RequiredArgsConstructor
public class ActReModelServiceImpl implements ActReModelService {

    private final ActReModelRepository actReModelRepository;
    private final ActReModelMapper actReModelMapper;
    private final ProcessCategoryRepository processCategoryRepository;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public Map<String, Object> queryAll(ActReModelQueryCriteria criteria, Pageable pageable) {
        Page<ActReModel> page = actReModelRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        page.getContent().forEach(actReModel ->{
            if(StringUtils.isNotEmpty(actReModel.getCategory())){
                //查询流程分类名称（事项）
                String categoryName = processCategoryRepository.findCategoryNameByCategoryId(actReModel.getCategory());
                actReModel.setCategoryName(categoryName);
            }
        });
        return PageUtil.toPage(page.map(actReModelMapper::toDto));
    }

    @Override
    public List<ActReModelDto> queryAll(ActReModelQueryCriteria criteria) {
        return actReModelMapper.toDto(actReModelRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public ActReModelDto findById(String id) {
        ActReModel actReModel = actReModelRepository.findById(id).orElseGet(ActReModel::new);
        ValidationUtil.isNull(actReModel.getId(), "ActReModel", "id", id);
        return actReModelMapper.toDto(actReModel);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActReModelDto create(ActReModel resources) {
        //属性对拷
        Model model = repositoryService.newModel();
        model.setKey(resources.getKey());
        model.setName(resources.getName());
        //保存模型
        repositoryService.saveModel(model);
        return actReModelMapper.toDto(actReModelRepository.getOne(model.getId()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ActReModel resources) {
        ActReModel actReModel = actReModelRepository.findById(resources.getId()).orElseGet(ActReModel::new);
        ValidationUtil.isNull(actReModel.getId(), "ActReModel", "id", resources.getId());
        actReModel.copy(resources);
        actReModelRepository.save(actReModel);
    }

    @Override
    public void deleteAll(String[] ids) {
        for (String id : ids) {
            actReModelRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<ActReModelDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ActReModelDto actReModel : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("乐观锁", actReModel.getRev());
            map.put("名称", actReModel.getName());
            map.put("模型的关键字", actReModel.getKey());
            map.put("分类", actReModel.getCategory());
            map.put("创建时间", actReModel.getCreateTime());
            map.put("最新修改时间", actReModel.getLastUpdateTime());
            map.put("版本", actReModel.getVersion());
            map.put("以json格式保存流程定义的信息", actReModel.getMetaInfo());
            map.put("部署ID", actReModel.getDeploymentId());
            map.put("编辑源值ID", actReModel.getEditorSourceValueId());
            map.put("编辑源额外值ID", actReModel.getEditorSourceExtraValueId());
            map.put("租户", actReModel.getTenantId());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public ObjectNode getModel(String modelId) {
        Model model = repositoryService.getModel(modelId);

        //组装流程模型json数据
        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put("modelId", model.getId());
        modelNode.put("name", model.getName());
        modelNode.put("key", model.getKey());
        modelNode.put("description", JSONObject.parseObject(model.getMetaInfo()).getString("description"));
        modelNode.putPOJO("lastUpdated", model.getLastUpdateTime());
        byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
        if (null != modelEditorSource && modelEditorSource.length > 0) {
            try {
                ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(modelEditorSource);
                editorJsonNode.put("modelType", "model");
                modelNode.put("model", editorJsonNode);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return modelNode;
    }

    @Override
    public void createModel(ModelVo modelVo) {

        String id = null;
        try {
            Model model = repositoryService.newModel();
            String key = modelVo.getKey();
            ObjectNode modelNode = objectMapper.createObjectNode();
            modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelVo.getName());
            //modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelVo.getDescription());
            //modelNode.put(ModelDataJsonConstants.MODEL_REVISION, "1");

            model.setName(modelVo.getName());
            model.setKey(key);
            //模型分类 结合自己的业务逻辑
            model.setCategory(modelVo.getCategory());

            model.setMetaInfo(modelNode.toString());

            repositoryService.saveModel(model);
            id = model.getId();

            //完善ModelEditorSource
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace",
                    "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);
            repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void saveModel(String modelId, MultiValueMap values) {
        try {
            //模型信息
            String jsonXml = (String) values.get("json_xml");
            String svgXml = (String) values.get("svg_xml");
            String name = (String) values.get("name");
            String description = (String) values.get("description");
            //模型关键字
            String key = (String)values.getFirst("key");

            //模型
            Model model = repositoryService.getModel(modelId);
            if (null == model) {
                model = repositoryService.newModel();
            }

            //流程的json
            ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

            modelJson.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelJson.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            model.setMetaInfo(modelJson.toString());
            model.setName(name);
            //流程key
            model.setKey(StringUtils.defaultString(key));

            //保存到act_re_model
            repositoryService.saveModel(model);
            repositoryService.addModelEditorSource(model.getId(), model.toString().getBytes("utf-8"));
            //bpmn文件保存到eladmin-system -> resources -> processes 文件夹下
        } catch (IOException e) {
            throw new BadRequestException(HttpStatus.OK, "流程保存发生异常");
        }

    }


}